package edu.uoc.vmerinom.tfc.service;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.log.Log;

import edu.uoc.vmerinom.tfc.domain.Grupo;

/**
 * Clase de servicios con las operaciones de acceso a base de datos para el
 * módulo de grupos.
 * 
 * @author Víctor Manuel Merino Martínez
 * 
 */
@Name("gruposService")
@Scope(ScopeType.CONVERSATION)
public class GruposService {
	/**
	 * Gestor de entidades.
	 */
	@In(create = true)
	EntityManager entityManager;

	/**
	 * Log para la trazabilidad de errores.
	 */
	@Logger
	Log log;

	/**
	 * Devuelve un listado de grupos ordenados por nombre.
	 * 
	 * @return Listado de grupos
	 */
	@SuppressWarnings("unchecked")
	public List<Grupo> obtenerGrupos() {
		if (log.isDebugEnabled()) {
			log.debug("GruposService.obtenerGrupos()");
		}
		final String query = "select distinct g from Grupo g left join fetch g.componentes order by g.nombre";
		log.info(query);
		return entityManager.createQuery(query).getResultList();
	}

	/**
	 * Devuelve un listado de grupos activos ordenados por nombre, es decir, los
	 * grupos que tienen la fecha de baja a <code>null</code> o bien que sea
	 * posterior a la fecha actual.
	 * 
	 * @return Listado de grupos activos
	 */
	@SuppressWarnings("unchecked")
	public List<Grupo> obtenerGruposActivos() {
		if (log.isDebugEnabled()) {
			log.debug("GruposService.obtenerGruposActivos()");
		}
		final String query = "select distinct g from Grupo g left join fetch g.componentes where g.baja is null or g.baja > :currentDate order by g.nombre";
		log.info(query);
		return entityManager.createQuery(query).setParameter("currentDate", new Date()).getResultList();
	}

	/**
	 * Devuelve el grupo cuyo nombre coincida con el que recibe por parámetros.
	 * Permite filtrar por el identificador: si el identificador recibido es
	 * distinto de <code>null</code>, se buscará el grupo cuyo nombre coincida
	 * con el que recibe por parámetros, pero que no tenga el mismo
	 * identificador recibido. Si el grupo no se encuentra, el método devolverá
	 * <code>null</code>.
	 * 
	 * @param nombre
	 *            Nombre del grupo
	 * @param id
	 *            Identificador del grupo
	 * @return Grupo con el nombre recibido por parámetros
	 */
	public Grupo obtenerGrupo(String nombre, Integer id) {
		if (log.isDebugEnabled()) {
			log.debug("GruposService.obtenerGrupo(nombre:" + nombre + ", id:" + id + ")");
		}
		final StringBuffer queryString = new StringBuffer("from Grupo g where upper(g.nombre) like upper(:nombre)");
		if (id != null) {
			queryString.append(" and g.id != :id");
		}

		log.info(queryString);
		Query query = entityManager.createQuery(queryString.toString()).setParameter("nombre", nombre);
		if (id != null) {
			query.setParameter("id", id);
		}
		Grupo grupo = null;
		try {
			grupo = (Grupo) query.getSingleResult();
		} catch (final NoResultException e) {
			grupo = null;
		}
		return grupo;
	}

	/**
	 * Actualiza el estado del grupo para poder visualizar los datos actuales de
	 * base de datos.
	 * 
	 * @param grupo
	 *            Grupo a actualizar
	 */
	public void actualizarEstadoGrupo(Grupo grupo) {
		if (log.isDebugEnabled()) {
			log.debug("GruposService.actualizarEstadoGrupo(grupo:" + grupo + ")");
		}
		if (grupo != null && grupo.getId() != null) {
			entityManager.refresh(grupo);
		}
	}

	/**
	 * Inserta o modifica los datos del grupo que recibe por parámetros.
	 * 
	 * @param grupo
	 *            Grupo a insertar/modificar
	 */
	@Transactional
	public void insertarModificarGrupo(Grupo grupo) {
		if (log.isDebugEnabled()) {
			log.debug("GruposService.insertarModificarGrupo(grupo:" + grupo + ")");
		}
		if (grupo != null) {
			final Date hoy = new Date(System.currentTimeMillis());
			if (grupo.getId() == null) {
				grupo.setCreado(hoy);
			}
			grupo.setModificado(hoy);
			entityManager.persist(grupo);
		}
		entityManager.flush();
	}
}
